package com.haixiaoke.handle;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.haixiaoke.common.annotation.Dict;
import com.haixiaoke.common.enums.DefaultEnum;
import com.haixiaoke.common.utils.DictUtils;
import com.haixiaoke.common.utils.spring.SpringUtils;
import com.haixiaoke.domain.CustomDict;
import com.haixiaoke.mapper.CustomDictMapper;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 字典翻译处理器
 *
 * @author zhiping
 */
@Component
public class DictHandle {


    /**
     * 使用缓存，避免列表数据多次进行字典查询
     * key: @dict注解字段的 fieldName;
     * value: 字典数据, 如 {"key": "value", "key1": "value2" }
     */
    private static ThreadLocal<Map<String, Map<String, String>>> cache = ThreadLocal.withInitial(ConcurrentHashMap::new);

    public static Object parseResult(Object result) throws Exception {
        // 判断空
        if (Objects.isNull(result)) {
            return null;
        }
        // 判断结果类型
        if (result instanceof List) {
            // list类型
            List<Object> list = Lists.newArrayList();
            for (Object obj : (List<Object>) result) {
                list.add(parseDict(obj));
            }
            return list;
        } else {
            // 单实例对象类型
            return parseDict(result);
        }
    }

    /**
     * 字典转换
     *
     * @param obj
     */
    private static Object parseDict(Object obj) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        Field[] fields = obj.getClass().getDeclaredFields();
        // 非空判断
        if (ObjectUtil.isEmpty(fields)) {
            return null;
        }
        for (Field field : fields) {
            // 判断每一个字典是否有Dict注解
            if (Objects.nonNull(field.getAnnotation(Dict.class))) {
                handleDict(obj, field);
            }
        }
        return obj;
    }

    /**
     * 处理字典注解的字段
     */
    private static void handleDict(Object obj, Field field) throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
        Dict dict = field.getAnnotation(Dict.class);
        String localDict = dict.localDict();
        String databaseDictType = dict.databaseDictType();
        String tableName = dict.tableName();

        if (StrUtil.isNotEmpty(localDict)) {
            // 指定Dict的 "localDict"
            handleLocalDict(obj, field, dict);
        } else if (StrUtil.isNotEmpty(databaseDictType)) {
            // 指定Dict的 databaseDictType
            handleDatabaseDict(obj, field, dict);
        } else if (StrUtil.isNotEmpty(tableName)) {
            // 指定Dict的 tableName、valueField 、labelField
            handleCustomDict(obj, field, dict);
        } else {
            // 指定Dict的 enumClass，不指定则默认DefaultEnum枚举
            handleEnum(obj, field, dict);
        }
    }


    /**
     * 处理本地字典转换的逻辑
     *
     * @param obj
     * @param field
     * @param dict
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static void handleLocalDict(Object obj, Field field, Dict dict) throws
            NoSuchFieldException, IllegalAccessException {
        String suffix = dict.suffix();
        String dictVal = dict.localDict();
        field.setAccessible(true);
        Object key = field.get(obj);
        if (StrUtil.isEmpty(dictVal) || Objects.isNull(key)) {
            return;
        }

        String fieldName = field.getName();
        Map<String, String> dictValMap = getLocalDictMap(fieldName, dictVal);

        if (StrUtil.endWith(fieldName, "Id")) {
            fieldName = StrUtil.subBefore(fieldName, "Id", true);
        }

        Field name = obj.getClass().getDeclaredField(fieldName + suffix);
        name.setAccessible(true);
        name.set(obj, dictValMap.get(key.toString()));
        name.setAccessible(false);
        field.setAccessible(false);
    }


    /**
     * 处理数据库字典转换的逻辑
     *
     * @param obj
     * @param field
     * @param dict
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static void handleDatabaseDict(Object obj, Field field, Dict dict) throws
            NoSuchFieldException, IllegalAccessException {
        String suffix = dict.suffix();
        String dictType = dict.databaseDictType();
        field.setAccessible(true);
        Object key = field.get(obj);
        if (StrUtil.isEmpty(dictType) || Objects.isNull(key)) {
            return;
        }
        String fieldName = field.getName();
        if (fieldName.endsWith("Id")) {
            fieldName = StrUtil.subBefore(fieldName, "Id", true);
        }
        Field name = obj.getClass().getDeclaredField(fieldName + suffix);
        name.setAccessible(true);
        name.set(obj, DictUtils.getDictLabel(dictType, Convert.toStr(key)));
        name.setAccessible(false);
        field.setAccessible(false);
    }


    /**
     * 处理指定表数据作为字典的转换的逻辑
     *
     * @param obj
     * @param field
     * @param dict
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private static void handleCustomDict(Object obj, Field field, Dict dict) throws
            NoSuchFieldException, IllegalAccessException {

        // 如果需要翻译的值为空, 直接turn
        field.setAccessible(true);
        Object key = field.get(obj);
        if (Objects.isNull(key)) {
            return;
        }

        String suffix = dict.suffix();
        String tableName = dict.tableName();
        String valueField = dict.valueField();
        String labelField = dict.labelField();

        // 如果注解信息不全, 就不翻译
        if (StrUtil.isBlank(tableName) || StrUtil.isBlank(valueField) || StrUtil.isBlank(labelField)) {
            System.out.println("注解信息不全,不翻译!");
            return;
        }

        Map<String, String> customDictMap = getCustomDictMap(tableName, valueField, labelField);

        String fieldName = field.getName();
        if (fieldName.endsWith("Id")) {
            fieldName = StrUtil.subBefore(fieldName, "Id", true);
        }
        Field name = obj.getClass().getDeclaredField(fieldName + suffix);
        name.setAccessible(true);
        name.set(obj, customDictMap.get(key.toString()));
        name.setAccessible(false);
        field.setAccessible(false);

    }

    /**
     * 处理枚举作为字典的转换逻辑
     *
     * @param obj
     * @param field
     * @param dict
     */
    private static void handleEnum(Object obj, Field field, Dict dict) throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {

        // 如果需要翻译的值为空, 直接turn
        field.setAccessible(true);
        Object key = field.get(obj);
        if (Objects.isNull(key)) {
            return;
        }

        Class<? extends Enum<?>> clazz = dict.enumClass();
        String clazzName = clazz.getName();
        String defaultEnumName = DefaultEnum.class.getName();
        if (StrUtil.equals(clazzName, defaultEnumName)) {
            return;
        }

        String valueField = dict.valueField();
        String labelField = dict.labelField();

        Map<String, String> enumDictMap = getEnumDictMap(clazz, valueField, labelField);
        String value = enumDictMap.get(key.toString());

        String fieldName = field.getName();
        if (fieldName.endsWith("Id")) {
            fieldName = StrUtil.subBefore(fieldName, "Id", true);
        }
        Field name = obj.getClass().getDeclaredField(fieldName + dict.suffix());
        name.setAccessible(true);
        name.set(obj, value);
        name.setAccessible(false);
        field.setAccessible(false);

    }


    /**
     * 获取本地字典值列表，格式要求：1:启用;2:禁用;
     *
     * @param fieldName 注解具体的字段名称
     * @param dictVal   字典键值对
     * @return 字典列表
     */
    private static Map<String, String> getLocalDictMap(String fieldName, String dictVal) {
        if (StrUtil.isEmpty(dictVal)) {
            return Collections.emptyMap();
        }
        Map<String, Map<String, String>> dictMap = cache.get();
        if (dictMap.containsKey(fieldName)) {
            return dictMap.get(fieldName);
        }
        Map<String, String> valMap = new HashMap<>();
        String[] split = dictVal.split(";");
        for (String s : split) {
            String[] val = s.split(":");
            if (val.length != 2) {
                continue;
            }
            valMap.put(val[0], StrUtil.trim(val[1]));
        }
        dictMap.put(fieldName, valMap);
        cache.set(dictMap);
        return valMap;
    }

    private static Map<String, String> getCustomDictMap(String tableName, String valueField, String labelField) {
        Map<String, Map<String, String>> dictMap = cache.get();
        Map<String, String> customDictMap = dictMap.get(tableName + "_" + valueField + "_" + labelField);
        if (CollectionUtil.isEmpty(customDictMap)) {
            CustomDictMapper mapper = SpringUtils.getBean(CustomDictMapper.class);
            List<CustomDict> customDicts = mapper.selectDict(tableName, valueField, labelField);
            customDictMap = new HashMap<>();
            for (CustomDict customDict : customDicts) {
                String value = customDict.getValue();
                String label = customDict.getLabel();
                customDictMap.put(value, label);
            }
            dictMap.put(tableName + "_" + valueField + "_" + labelField, customDictMap);
            cache.set(dictMap);
        }
        return customDictMap;
    }


    private static Map<String, String> getEnumDictMap(Class clazz, String valueField, String labelField) {

        Map<String, Map<String, String>> dictMap = cache.get();
        Map<String, String> enumDictMap = dictMap.get(clazz.getName() + "_" + valueField + "_" + labelField);

        if (CollectionUtil.isEmpty(enumDictMap)) {

            Map<String, String> valueFieldMap = EnumUtil.getNameFieldMap(clazz, valueField);
            Map<String, String> labelFieldMap = EnumUtil.getNameFieldMap(clazz, labelField);

            // 如果是  SUCCESS, FAIL 这样的枚举, value是枚举的ordinal, label是枚举的name
            if (StrUtil.isBlank(valueField) || StrUtil.isBlank(labelField)) {
                List<String> names = EnumUtil.getNames(clazz);
                for (int i = 0; i < names.size(); i++) {
                    enumDictMap.put(Convert.toStr(i), names.get(i));
                }
                dictMap.put(clazz.getName() + "_" + valueField + "_" + labelField, enumDictMap);
                cache.set(dictMap);
                return enumDictMap;
            }

            for (String key : valueFieldMap.keySet()) {
                String value = valueFieldMap.get(key);
                String label = labelFieldMap.get(key);
                enumDictMap.put(value, label);
            }
            dictMap.put(clazz.getName() + "_" + valueField + "_" + labelField, enumDictMap);
            cache.set(dictMap);
        }
        return enumDictMap;
    }


    /**
     * 清除缓存
     */
    public static void clearCache() {
        cache.remove();
    }

}
